package imgo

import (
	"bytes"
	"fmt"
	"log"
	"net"
	"sync"
	"time"
)

// Message 消息载体
type Message struct {
	//OriginMsg 信息载体 被传入
	OriginMsg *[]byte
	//From 消息来源
	From *net.Conn
}

// WorkRoutine 工作携程对象
type WorkRoutine struct {
	//Conn 链接指针
	Conn *net.Conn
	//Conn 链接的使用锁
	ConnLocker *sync.Mutex
	//ChanIn 监听时将链接收到的消息放入的信道
	ChanIn chan *[]byte
	//ChanOut 写入时将消息写入的信道
	ChanOut chan *[]byte
	//Exit 需要关闭时发送的信道
	Exit chan *net.Conn
}

// IWorkRoutine 接口 需要继承 WorkRoutine 的属性 其包含循环监听方法与循环写入方法
type IWorkRoutine interface {
	// Copy 该方法需要返回一个全新地址的 IWorkRoutine 其内部属性自定义
	Copy() IWorkRoutine
	// ReadListener 循环监听 传入本方法关闭时defer返回的信道
	//该方法需要指定为 WorkRoutine 所有 并使用 chanIn作为写入信道
	ReadListener(worker *WorkRoutine)
	// WriteLooper 循环写入 传入本方法关闭时defer返回的信道
	//同上 该方法 WorkRoutine 所有 使用 chanOut作为监听的信道
	WriteLooper(worker *WorkRoutine)
}

// defaultIWorkRoutine 默认实现
type defaultIWorkRoutine struct {
	delay int64
	log   bool
}

// NewDefaultIWorkRoutine 默认实现的构造方法
func NewDefaultIWorkRoutine(delay int64, log bool) *defaultIWorkRoutine {
	if delay == 0 {
		delay = 20
	}
	return &defaultIWorkRoutine{delay: delay, log: log}
}

//ReadListener 实现接口 并注意捕获异常以避免影响主程序
func (d *defaultIWorkRoutine) ReadListener(worker *WorkRoutine) {
	defer func() {
		err := recover()
		if err != nil {
			log.Println(" -- default read listener throw err : ", err)
		}
	}()
	for {
		if worker.Conn == nil {
			break
		}
		data := make([]byte, 64, 64)
		//read
		worker.ConnLocker.Lock()
		read, err := (*worker.Conn).Read(data)
		worker.ConnLocker.Unlock()
		if err != nil {
			worker.Exit <- worker.Conn
			break
		}
		data = data[:read]
		if d.log {
			s := fmt.Sprintf(" <<< from %s msg %s \n", (*worker.Conn).RemoteAddr(), bytes.NewBuffer(data).String())
			fmt.Print(s)
		}
		worker.ChanIn <- &data
		time.Sleep(time.Duration(d.delay))
	}
}

// WriteLooper 实现的写入方法
func (d *defaultIWorkRoutine) WriteLooper(worker *WorkRoutine) {
	defer func() {
		err := recover()
		if err != nil {
			log.Println(" -- default write looper throw err : ", err)
		}
	}()
	for {
		if worker.Conn == nil {
			break
		}
		if b, ok := <-worker.ChanOut; ok {
			//write
			worker.ConnLocker.Lock()
			write, err := (*worker.Conn).Write(*b)
			worker.ConnLocker.Unlock()
			if err != nil || write != len(*b) {
				worker.Exit <- worker.Conn
				break
			}
			if d.log {
				s := fmt.Sprintf(" >>> to %s msg %s \n", (*worker.Conn).RemoteAddr(), string(*b))
				fmt.Print(s)
			}
		}
	}
}

// Copy 实现的复制方法
func (d *defaultIWorkRoutine) Copy() IWorkRoutine {
	dd := defaultIWorkRoutine{
		delay: d.delay,
		log:   d.log,
	}
	return &dd
}
